package roborally.program.conditions;

import be.kuleuven.cs.som.annotate.*;
import roborally.model.Robot;

/**
 * A class for dealing with or-conditions: (or(condition)(condition)).  
 * 
 * @inar	The first condition of each or-condition must be valid.
 * 			| canHaveAsCondition(getFirstCondition())
 * @invar	The second condition of each or-condition must be valid.
 * 			| canHaveAsCondition(getSecondCondition())
 * 
 * @version	1.0
 * @author  Pieter Robberechts	(1e Bach Informatica)
 * @author	Jeroen Sanders		(1e Bach Informatica)
 *
 */
public class Or extends Condition {

	/**
	 * Initialize this new or-condition with a line number and two conditions.
	 * 
	 * @param 	firstCondition
	 * 			The first condition to be evaluated.
	 * @param 	secondCondition
	 * 			The second condition to be evaluated.
	 * @pre		The given first condition should be valid.
	 * 			| canHaveAsCondition(firstCondition)
	 * @pre		The given second condition should be valid.
	 * 			| canHaveAsCondition(secondCondition)
	 * @post	The first condition of this or-command is set to the given condition.
	 * 			| new.getFirstCondition() == firstCondition
	 * @post	The second condition of this or-command is set to the given condition.
	 * 			| new.getSecondCondition() == secondCondition
	 */
	public Or(int lineNb, Condition firstCondition, Condition secondCondition) {
		super(lineNb);
		assert( canHaveAsCondition(firstCondition) );
		assert( canHaveAsCondition(secondCondition) );
		this.firstCondition = firstCondition;
		this.secondCondition = secondCondition;
	}
	
	/**
	 * Variable registering the first condition to be evaluated.
	 */
	private final Condition firstCondition;
	
	/**
	 * Variable registering the second condition to be evaluated.
	 */
	private final Condition secondCondition;
	
	/**
	 * Return the first condition to be evaluated.
	 */
	@Basic @Raw @Immutable
	public Condition getFirstCondition() {
		return firstCondition;
	}

	/**
	 * Return the second condition to be evaluated.
	 */
	@Basic @Raw @Immutable
	public Condition getSecondCondition() {
		return secondCondition;
	}
	
	/**
	 * Check whether the given condition is a valid one for an or-condition.
	 * 
	 * @param	condition
	 * 			The condition to check for whether it is a valid one.
	 * @return	Return true if and only if the given condition is effective;
	 * 			else return false.
	 * 			| result == ( condition != null)
	 */
	@Raw
	public boolean canHaveAsCondition(Condition condition) {
		return ( condition != null );
	}
	
	/**
	 * Evaluate this condition for a given robot.
	 * 
	 * @return	Return true if and only if the first condition or the second condition 
	 * 			of this or-condition evaluates to true; else return false.
	 * 			| result == ( super.evaluate(robot) && 
	 *			|			  ( getFirstCondition().evaluate(robot) || 
	 *			|				getSecondCondition().evaluate(robot) ) )
	 */
	@Override
	public boolean evaluate(Robot robot) {
		super.evaluate(robot);
		return ( super.evaluate(robot) && 
				( getFirstCondition().evaluate(robot) || 
						getSecondCondition().evaluate(robot) ) );
	}
	
	/**
	 * Return a textual representation of this or-condition,
	 * formatted in accordance with its position in the program.
	 * 
	 * @return	The result is a pretty formatted string of this or-condition,
	 * 			taking in account his relative position in the program.
	 * 			| result == 
	 * 			|		getIndentation(indentationLevel) + "(or\n" + 
	 *			|		getFirstCondition().prettyFormat(indentationLevel+1) + "\n" + 
	 *			|		getSecondCondition().prettyFormat(indentationLevel+1) + "\n)"
	 */
	@Override
	public String prettyFormat(int indentationLevel) {
		return getIndentation(indentationLevel) + "(or\n" + 
				getFirstCondition().prettyFormat(indentationLevel+1) + "\n" + 
				getSecondCondition().prettyFormat(indentationLevel+1) + "\n)";
	}

}
